home *** CD-ROM | disk | FTP | other *** search
/ Aminet 34 / Aminet 34 (2000)(Schatztruhe)[!][Dec 1999].iso / Aminet / dev / c / GED_Scripts.lha / GED_Scripts / Mirror-Source / funcs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-14  |  11.4 KB  |  415 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  mirror.api ©1999 Dietmar Eilert
  4.  Improved and optimized to NewMirror.api by Christian Hattemer
  5.  
  6.  API plug-in. Highlights matching bracket if cursor is moved over a bracket.
  7.  
  8.  Compiles with StormC
  9.  
  10.  So muß ein Source aussehen, dann klappts auch mitm Nachbarn.
  11.  
  12.  -------------------------------------------------------------------------------
  13.  
  14. */
  15.  
  16. #include "defs.h"
  17.  
  18. // macros
  19.  
  20. /* Parameter: UBYTE c
  21.    Result   : TRUE if c is a bracket
  22. */
  23. #define IsABracket(c) (((c) == '(' || (c) == ')' || (c) == '{' || (c) == '}' || (c) == '[' || (c) == ']') ? TRUE : FALSE)
  24.  
  25. /* Parameter: struct EditConfig *config
  26.    Result   : TRUE if there is no user-defined block, i.e. either no block at all or a
  27.               marked bracket only (possibly marked by us).
  28. */
  29. #define NoUserBlock(config) (((config->Marker == BLOCKMODE_NONE) || FindMarkedBracket(config)) ? TRUE : FALSE)
  30.  
  31. /// "prototypes"
  32.  
  33. // library functions
  34.  
  35. Prototype struct APIClient * LibCall APIMountClient(REG(a0) struct APIMessage *apiMsg, REG(a1) char *args);
  36. Prototype void               LibCall APICloseClient(REG(a0) struct APIClient *handle, REG(a1) struct APIMessage *apiMsg);
  37. Prototype void               LibCall APIBriefClient(REG(a0) struct APIClient *handle, REG(a1) struct APIMessage *apiMsg);
  38. Prototype void               LibCall APIFree       (REG(a0) struct APIClient *handle, REG(a1) struct APIOrder *apiOrder);
  39.  
  40. // private functions
  41.  
  42. Prototype void Dispatch         (struct APIMessage *apiMsg);
  43. Prototype BOOL FindMarkedBracket(struct EditConfig *config);
  44. Prototype BOOL MatchingBracket  (struct APIMessage *apiMsg, UBYTE examine);
  45.  
  46. // the following line determines if online checks are enabled
  47.  
  48. #undef ONLINECHECK
  49. //#define ONLINECHECK
  50. ///
  51. /// "library functions"
  52.  
  53. struct APIClient * LibCall APIMountClient(REG(a0) struct APIMessage *apiMsg, REG(a1) char *args)
  54. {
  55.    static struct APIClient apiClient;
  56.  
  57.    apiClient.api_APIVersion = API_INTERFACE_VERSION;
  58.    apiClient.api_Version    = 3;
  59.    apiClient.api_Name       = "NewMirror";
  60.    apiClient.api_Info       = "Bracket highlighting";
  61.    apiClient.api_Commands   = NULL;
  62.    apiClient.api_Serial     = 0;
  63.    apiClient.api_Classes    = API_CLASS_SYSTEM | API_CLASS_KEY;
  64.    apiClient.api_Area       = NULL;
  65.  
  66.    return &apiClient;
  67. }
  68.  
  69. void LibCall APICloseClient(REG(a0) struct APIClient *handle, REG(a1) struct APIMessage *apiMsg)
  70. {
  71.    // no ressources to be freed
  72. }
  73.  
  74. void LibCall APIBriefClient(REG(a0) struct APIClient *handle, REG(a1) struct APIMessage *apiMsg)
  75. {
  76.    struct APIMessage *msg;
  77.  
  78.    // handle host's command notify
  79.  
  80.    for (msg = apiMsg; msg; msg = msg->api_Next)
  81.    {
  82.       if (msg->api_State == API_STATE_NOTIFY)
  83.       {
  84.          switch (msg->api_Class)
  85.          {
  86.             case API_CLASS_KEY:
  87.                Dispatch(msg); // useless fallthru, but it's short...
  88.  
  89.             case API_CLASS_SYSTEM:
  90.                break;
  91.  
  92.             default:
  93.                msg->api_Error = API_ERROR_UNKNOWN;
  94.          }
  95.       }
  96.    }
  97. }
  98.  
  99. void LibCall APIFree(REG(a0) struct APIClient *handle, REG(a1) struct APIOrder *apiOrder)
  100. {
  101.    // no ressources to be freed
  102. }
  103.  
  104. ///
  105. /// "private functions"
  106.  
  107. /* --------------------------------- Dispatch ----------------------------------
  108.  
  109.  Dispatch incoming API event
  110.  
  111. */
  112.  
  113. void Dispatch(struct APIMessage *apiMsg)
  114. {
  115.    struct EditConfig *config = (struct EditConfig *)apiMsg->api_Instance->api_Environment;
  116.  
  117.    if (NoUserBlock(config))
  118.    {
  119.       UBYTE ascii = config->CurrentBuffer[config->Column];
  120.  
  121.       if (IsABracket(ascii))
  122.       {
  123.          if (MatchingBracket(apiMsg, ascii) == FALSE)
  124.          {
  125.             if (FindMarkedBracket(config))
  126.             {
  127.                apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  128.             }
  129.          }
  130.       }
  131.       #ifndef ONLINECHECK
  132.       else if (FindMarkedBracket(config))
  133.       {
  134.          apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  135.       }
  136.       #endif
  137.       #ifdef ONLINECHECK
  138.       else
  139.       {
  140.          if (apiMsg->api_Action == API_ACTION_VANILLAKEY)
  141.          {
  142.             if (config->Column)
  143.             {
  144.                ascii = (UBYTE)apiMsg->api_Data;
  145.  
  146.                // check character next to cursor
  147.  
  148.                config->Column--;
  149.  
  150.                // just typed by user?
  151.  
  152.                if (config->CurrentBuffer[config->Column] == ascii)
  153.                {
  154.                   if (MatchingBracket(apiMsg, ascii) == FALSE)
  155.                   {
  156.                      if (FindMarkedBracket(config))
  157.                      {
  158.                         apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  159.                      }
  160.                   }
  161.                }
  162.                else if (FindMarkedBracket(config))
  163.                {
  164.                   apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  165.                }
  166.  
  167.                config->Column++;
  168.             }
  169.          }
  170.          else if (FindMarkedBracket(config))
  171.          {
  172.             apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  173.          }
  174.       }
  175.       #endif
  176.    }
  177. }
  178. /* ----------------------------- FindMarkedBracket -----------------------------
  179.  
  180.  Return TRUE if a single bracket has been marked (probably by us)
  181.  
  182. */
  183.  
  184. BOOL FindMarkedBracket(struct EditConfig *config)
  185. {
  186.    if (config->Marker == BLOCKMODE_CHAR)
  187.    {
  188.       if (config->BlockStartY == config->BlockEndY)
  189.       {
  190.          if (config->BlockStartX == config->BlockEndX)
  191.          {
  192.             UWORD pos = config->BlockStartX;
  193.  
  194.             if (config->BlockStartY == config->Line)
  195.             {
  196.                if (pos < config->CurrentLen)
  197.                {
  198.                   return IsABracket(config->CurrentBuffer[pos]);
  199.                }
  200.             }
  201.             else
  202.             {
  203.                struct LineNode *lineNode = config->TextNodes + config->BlockStartY;
  204.  
  205.                if (pos < lineNode->Len)
  206.                {
  207.                   return IsABracket(lineNode->Text[pos]);
  208.                }
  209.             }
  210.          }
  211.       }
  212.    }
  213.  
  214.    return FALSE;
  215. }
  216.  
  217.  
  218. /* ------------------------------- MatchingBracket -----------------------------
  219.  
  220.  Find matching bracket. Ignore brackets preceeded by '\' (ASCII 92, TeX
  221.  style construction used to insert a bracket into text).
  222.  
  223.  Return TRUE if matching bracket was found, else FALSE.
  224.  
  225.  \} ............ ignored      (TEX constant)
  226.  \\} ........... not ignored  (TEX bracket)
  227.  
  228. */
  229.  
  230. BOOL MatchingBracket(struct APIMessage *apiMsg, UBYTE examine)
  231. {
  232.    UBYTE *known = "(){}[]";
  233.    WORD   step;
  234.  
  235.    struct EditConfig *config = (struct EditConfig *)apiMsg->api_Instance->api_Environment;
  236.  
  237.    for (step = 1; *known; known++, step = -step)
  238.    {
  239.       if (examine == *known)
  240.       {
  241.          WORD   column;
  242.          UBYTE *current;
  243.          BOOL   isTEX;
  244.  
  245.          column  = config->Column;
  246.          current = config->CurrentBuffer;
  247.  
  248.          if ((column > 0) && (current[column - 1] == '\\'))
  249.          {
  250.             if ((column > 1) && (current[column - 2] == '\\'))
  251.             {
  252.                 isTEX = FALSE;
  253.             }
  254.             else
  255.             {
  256.                 isTEX = TRUE;
  257.             }
  258.          }
  259.          else
  260.          {
  261.             isTEX = FALSE;
  262.          }
  263.  
  264.          if (isTEX == FALSE)
  265.          {
  266.             WORD   len, level, count, distance;
  267.             BOOL   success, inString;
  268.             ULONG  line;
  269.             UBYTE  twin;
  270.  
  271.             inString = FALSE;
  272.             success  = FALSE;
  273.  
  274.             line     = config->Line;
  275.             len      = config->CurrentLen;
  276.  
  277.             twin = *(known + step);
  278.  
  279.             count    =  0;
  280.             level    = -1;
  281.  
  282.             // modify the scan depth (default: 50 lines) to speed up the client
  283.             #define DIST_START 50
  284.  
  285.             for (distance = DIST_START; distance; distance--)
  286.             {
  287.                while ((column >= 0) && (column < len))
  288.                {
  289.                   UBYTE *next = current + column;
  290.  
  291.                   if ((*next == '\"') || (*next == '\''))
  292.                   {
  293.                      inString = !inString;
  294.                   }
  295.                   else if (!inString)
  296.                   {
  297.                      if ((column > 0) && (*(next - 1) == '\\'))
  298.                      {
  299.                         if ((column > 1) && (*(next - 2) == '\\'))
  300.                         {
  301.                            isTEX = FALSE;
  302.                         }
  303.                         else
  304.                         {
  305.                            isTEX = TRUE;
  306.                         }
  307.                      }
  308.                      else
  309.                      {
  310.                         isTEX = FALSE;
  311.                      }
  312.  
  313.                      if (!isTEX)
  314.                      {
  315.                         if (*next == twin)
  316.                         {
  317.                            if (level)
  318.                            {
  319.                               level--;
  320.                            }
  321.                            else
  322.                            {
  323.                               success = TRUE;
  324.                               break;
  325.                            }
  326.                         }
  327.                         else if (*next == *known)
  328.                         {
  329.                            level++;
  330.                            count++;
  331.                         }
  332.                      }
  333.                   }
  334.  
  335.                   column += step;
  336.                }
  337.  
  338.                if (success)
  339.                {
  340.                   BOOL adjacent = FALSE;
  341.  
  342.                   if (line == config->Line)
  343.                   {
  344.                      adjacent = (column == (config->Column + step));
  345.                   }
  346.  
  347.                   if (adjacent)
  348.                   {
  349.                      apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  350.                   }
  351.                   else
  352.                   {
  353.                      // block markers may not be used in fold headers
  354.  
  355.                      if (GET_FOLD(config->TextNodes + line))
  356.                      {
  357.                         return FALSE;
  358.                      }
  359.                      else
  360.                      {
  361.                         if ((distance == DIST_START) && ((config->Marker == BLOCKMODE_NONE) || ((line == config->BlockStartY) && (line == config->BlockEndY))))
  362.                         {
  363.                            apiMsg->api_Refresh = API_REFRESH_LINE;
  364.                         }
  365.                         else
  366.                         {
  367.                            if (config->Marker == BLOCKMODE_NONE)
  368.                            {
  369.                               apiMsg->api_Refresh = API_REFRESH_MARKER;
  370.                            }
  371.                            else
  372.                            {
  373.                               apiMsg->api_Refresh = API_REFRESH_DISPLAY;
  374.                            }
  375.                         }
  376.  
  377.                         config->Marker = BLOCKMODE_CHAR;
  378.  
  379.                         config->BlockStartX = config->BlockEndX = column;
  380.                         config->BlockStartY = config->BlockEndY = line;
  381.  
  382.                         return TRUE;
  383.                      }
  384.                   }
  385.                }
  386.                else
  387.                {
  388.                   line += step;
  389.                   inString = FALSE;
  390.  
  391.                   if ((line >= 0) && (line < config->Lines))
  392.                   {
  393.                      struct LineNode *lineNode = config->TextNodes + line;
  394.  
  395.                      current = lineNode->Text;
  396.                      len     = lineNode->Len;
  397.  
  398.                      column = (step == -1) ? len - 1 : 0;
  399.                   }
  400.                   else
  401.                   {                         // no matching bracket
  402.                      break;
  403.                   }
  404.                }
  405.             }
  406.  
  407.             break;
  408.          }
  409.       }
  410.    }
  411.  
  412.    return FALSE;
  413. }
  414.  
  415.